package com.iring.service.pay.impl;

import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.iring.domain.config.PayConfig;
import com.iring.domain.config.PaypalPaymentIntent;
import com.iring.domain.config.prop.PayPalProperties;
import com.iring.domain.config.prop.PayProperties;
import com.iring.domain.pay.OrderPayment;
import com.iring.domain.pay.PurchaseUnits;
import com.iring.domain.pay.check.PaypalCheck;
import com.iring.domain.pay.info.PayPalInfo;
import com.iring.domain.pay.res.PaypalRes;
import com.iring.exception.ParamInvalidException;
import com.iring.service.pay.PayService;
import com.paypal.api.payments.Amount;
import com.paypal.api.payments.Item;
import com.paypal.api.payments.Links;
import com.paypal.api.payments.RedirectUrls;
import com.paypal.base.rest.APIContext;
import com.paypal.base.rest.PayPalRESTException;

/**
 * @author wanggan
 */
@Service("paypal")
public class PaypalServiceImpl implements PayService<PayPalInfo, PaypalRes,PaypalCheck> {

    private static final Logger logger = LoggerFactory.getLogger(PaypalServiceImpl.class);

    @Autowired
    APIContext apiContext;

    @Autowired
    PayPalProperties payPalProperties;

    @Autowired
    PayProperties payProperties;

    @Override
    public PaypalRes createPay(PayPalInfo payPalInfo) {

        OrderPayment orderPayment = createPayment(payPalInfo);

        assert orderPayment != null;

        //TODO
        String orderHref = orderPayment.getLinks()
                .stream()
                .filter(link -> "approval_url".equals(link.getRel()))
                .map(Links::getHref)
                .findFirst()
                .orElse("");

        String tradeNo = orderPayment.getId();
        String status = orderPayment.getStatus();
        logger.info("create paypal order tradeNo={},status={}",tradeNo,status);

        PaypalRes payRes = new PaypalRes();
        payRes.setTradeNo(tradeNo);
        payRes.setState(status);
        payRes.setOrderHref(orderHref);
        //设置发票的编号
        payRes.setInvoiceNumber(orderPayment.getPurchaseUnits().get(0).getInvoice_number());
        return payRes;
    }

    @Override
    public PaypalCheck cancelPay(PayPalInfo payInfo) {
        String tradeNo = payInfo.getOrderId();
        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setId(tradeNo);
        try {
            orderPayment.delete(apiContext,tradeNo);
        } catch (PayPalRESTException e) {
            logger.info("cancel paypal order exception={}",e);
        }
        return null;
    }

    @Override
    public PaypalCheck checkPay(PaypalCheck paypalCheck) {
        String server = payProperties.getDomain();

        try {
            OrderPayment orderPayment = checkPayment(paypalCheck);

            String status = orderPayment.getStatus();
            logger.info("check payment tradeno={},status={}",paypalCheck.getTradeNo(),status);
            if ("complete".equalsIgnoreCase(status)) {
                paypalCheck.setPayResult(true);
            }
            paypalCheck.setPayStatus(status);
            if(orderPayment!=null&&orderPayment.getPayerInfo()!=null){
                paypalCheck.setPayerId(orderPayment.getPayerInfo().getPayerId());
            }else{
                paypalCheck.setPayerId(null);
            }

        } catch (PayPalRESTException ex) {
            Integer code = ex.getResponsecode();
            String msg = ex.getDetails().getMessage();
            //如果资源不可用，则直接定义为订单已经失效
            if(code == 404 && "Resource doesn't exist".equalsIgnoreCase(msg)){
                paypalCheck.setPayStatus(PayConfig.ORDER_FAILED);
            }else{
                logger.error("exception={}", ex);
            }
        }
        return  paypalCheck;
    }

    /**
     * 创建支付订单
     *
     * @param payPalInfo
     *            创建paypal订单需要的参数信息
     * @return 创建结果 {@link OrderPayment}
     */
    private OrderPayment createPayment(PayPalInfo payPalInfo) {

        //获取需要的金额
        String totalAmout = String.format("%.2f",payPalInfo.getTotal());

        //获取货币类型
        String currency = payPalProperties.getCurrency();

        //获取订单描述信息
        String orderDescribe = payProperties.getDescrible();

        List<PurchaseUnits> purchaseUnitsList = new ArrayList<>();
        //设置购买单元
        //设置金额
        Amount amount = new Amount();
        amount.setTotal(totalAmout);
        amount.setCurrency(currency);

        List<Item> payItemList = new ArrayList<>();
        // 对单个物品进行描述
        Item payItem = new Item(orderDescribe.toLowerCase(), "1", totalAmout, currency);
        payItem.setTax(String.format("%.2f", 0.00));
        payItemList.add(payItem);

        PurchaseUnits purchaseUnits = new PurchaseUnits();
        purchaseUnits.setReferenceId(orderDescribe.toLowerCase());
        purchaseUnits.setDescription(orderDescribe);
        purchaseUnits.setAmount(amount);
        purchaseUnits.setItems(payItemList);
        //设置发票单号
        purchaseUnits.setInvoice_number("invoice-"+payPalInfo.getOrderId());
        purchaseUnitsList.add(purchaseUnits);


        //设置订单的支付成功返回链接和取消链接通知url
        RedirectUrls redirectUrls = new RedirectUrls();
        redirectUrls.setCancelUrl(payPalProperties.getCancelUrl());
        redirectUrls.setReturnUrl(payPalProperties.getReturnUrl());

        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setIntent(PaypalPaymentIntent.SALE);
        orderPayment.setPurchaseUnits(purchaseUnitsList);
        orderPayment.setRedirectUrls(redirectUrls);
        try {
            return orderPayment.create(apiContext);
        } catch (PayPalRESTException e) {
            logger.info("create paypal order info failed={}",e);
            throw new ParamInvalidException(String.valueOf(e.getResponsecode()),e.getMessage());
        }
    }

    /**
     * 查询支付订单
     *
     * @param paypalCheck
     *            {@link PaypalCheck} 检查支付订单,校验结果的参数
     * @return 查询结果
     *
     * @throws PayPalRESTException
     *             异常
     */
    private OrderPayment checkPayment(PaypalCheck paypalCheck) throws PayPalRESTException {

        String tradeNo = paypalCheck.getTradeNo();
        OrderPayment orderPayment = new OrderPayment();
        orderPayment.setId(tradeNo);

        orderPayment = orderPayment.get(apiContext,tradeNo);

        String url = orderPayment.getLinks()
                .stream()
                .filter(links -> "capture".equals(links.getRel()))
                .map(Links::getHref)
                .findFirst()
                .orElse("");

        String status = orderPayment.getStatus();

        if(null!= url&& "COMPLETE".equalsIgnoreCase(status)||"APPROVED".equalsIgnoreCase(status)){
            orderPayment.setStatus("COMPLETE");
        }
        return orderPayment;
    }

}
